/* converts from an IBM picture to an apple image fragment */
/* extension is rag */

#include <stdio.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <dos.h>
#include <bios.h>
#include <malloc.h>
#include <string.h>    /* declares movedata function */

#define ENTERKEY   '\x0d' /* character generated by the Enter Key          */
#define ESCKEY     '\x1b' /* character generated by the Esc key            */

#define FUNCKEY    '\x00' /* first character generated by function keys    */
#define HOMEKEY    'G'    /* second character generated by Home key        */
#define ENDKEY     'O'    /* second character generated by End key         */
#define UPARROW    'H'    /* second character generated by up-arrow key    */
#define DOWNARROW  'P'    /* second character generated by down-arrow key  */
#define LEFTARROW  'K'    /* second character generated by left-arrow key  */
#define RIGHTARROW 'M'    /* second character generated by right-arrow key */
#define PGUP       'I'    /* second character generated by page up key     */
#define PGDOWN     'Q'    /* second character generated by page down key   */

/* screen modes */
#define TEXT     3
#define MED_RES  5
#define HI_RES   6

/* default adapter */
int ADAPTER=MED_RES;

#define   FRAMEBUFFER 0xb800
int       CGALEAF[2]={0,8192};
#define   CGALINE    80
#define   SCREENSIZE 16385

char far  *screenbuffer;

void STUFF_BUFF(void)
{
    screenbuffer = _fmalloc(SCREENSIZE);
}


int setcrtmode(unsigned _CRT_MODE)
{
    union REGS rin,rout;

    if ((_bios_equiplist() & 0x30) == 0x30)
        {
        printf("Sorry... Cga Compatible Displays Only...");
         exit(0);
        }

    rin.h.ah = 0;
    rin.h.al = _CRT_MODE;
    int86(0x10,&rin,&rout);
    return 0;

}


unsigned int byteword(unsigned char a, unsigned char b){return b<<8|a;}
unsigned char pcxheader[128];

int checkforpcx(char *name)
{
    FILE *fp; /* reads a ZSOFT .PCX header but ignores the color map */
    int i;    /* we only want CGA compatible full screens.           */

    unsigned int zsoft,version,codetype,pixbits;
    unsigned int xmin, ymin, xmax, ymax;
    unsigned int hres, vres;
    unsigned int no_planes, bytesperline;
    int invalid = -1, valid = 0, status=valid;

    /* read the file header */
    if((fp=fopen(name,"rb"))==NULL)return -1;
    for(i=0;i!=128;i++)pcxheader[i]=fgetc(fp);
    fclose(fp);

    zsoft   =pcxheader[0];
    version =pcxheader[1];
    codetype=pcxheader[2];
    pixbits =pcxheader[3];

    if(zsoft!=10)        status = invalid;
    if(codetype!=1)      status = invalid;
    if(pixbits != 2 )
       if(pixbits != 1)  status = invalid;

    xmin=byteword(pcxheader[4],pcxheader[5]);
    ymin=byteword(pcxheader[6],pcxheader[7]);
    xmax=byteword(pcxheader[8],pcxheader[9]);
    ymax=byteword(pcxheader[10],pcxheader[11]);
    hres=byteword(pcxheader[12],pcxheader[13]);
    vres=byteword(pcxheader[14],pcxheader[15]);
    no_planes   =pcxheader[65];
    bytesperline=byteword(pcxheader[66],pcxheader[67]);
    if(xmin != 0  )      status = invalid;
    if(ymin != 0  )      status = invalid;
    if(xmax != 319)
       if(xmax!=639)     status = invalid;
    if(ymax != 199)      status = invalid;
    if(hres != 320)
       if(hres!=640)     status = invalid;
       if(hres==640)ADAPTER=HI_RES;
       else ADAPTER=MED_RES;
    if(vres != 200)      status = invalid;
    if(no_planes!=1)     status = invalid;
    if(bytesperline !=80)status = invalid;
    /* we can ignore the color map since we        */
    /* are limiting ourselves to CGA modes         */
    /* so we will not handle over 2-bits per pixel */
    return status;

}


/* a microsoft compatible bsaved image format descriptor */
char BSAVED_header[7]={
    '\xfd','\x00','\xb8','\x00','\x00','\x00','\x40'};

int PCXREAD(char *pcxfilename)
{
    unsigned int byteoff=0,packet,width=0;
    FILE *fp;
    unsigned char byte,bytecount;
    long wordcount,target;

    if(checkforpcx(pcxfilename)==-1)return-1;
    fp = fopen(pcxfilename,"rb");

    target = filelength(fileno(fp));
    for(wordcount=0;wordcount!=128;wordcount++)byte=fgetc(fp);

    do{ bytecount=1;                          /* start with a seed count */
        byte=fgetc(fp);
        wordcount++;
                                              /* check to see if its raw */
        if(0xC0 == (0xC0 &byte)){             /* if its not, run encoded */
                    bytecount= 0x3f &byte;
                    byte=fgetc(fp);
                    wordcount++;
                    }
        for(packet=0;packet<bytecount;packet++){
                     screenbuffer[byteoff]=byte;
                     byteoff++;
                     }
        }while(wordcount<target);
        fclose(fp);
        return(0);
}

int B_READ(char *name)
{
    int fh,fh2,y,i,status=0;


    char headbuf[7];
    char linebuffer[CGALINE];
    int offset=0;                              /* window the YREGs */
    int bos;                                   /* bottom of screen */
    long target=16384,target2,header=7;
    /* open the file twice,eliminate the interleaf,read contiguous */

    if((fh = open(name,O_RDONLY|O_BINARY)) == -1)     status = -1;
    if((fh2 = open(name,O_RDONLY|O_BINARY)) == -1)    status = -1;
    if(status==0)read(fh,headbuf,7)                              ;
    for(i=0;i!=4;i++)if(status!=0 || headbuf[i]!=BSAVED_header[i]){
                                                      close(fh)  ;
                                                      close(fh2) ;
                                                      return -1  ;}

    target2=(target/2)+header          ;
    lseek(fh,(long)(header),SEEK_SET)  ;
    lseek(fh2,(long)(target2),SEEK_SET);
    bos=200                            ;/*filesize divide by scanlines*/

          for(y=0;y<bos;y+=2){
                read(fh,linebuffer,CGALINE);
                for(i=0;i!=CGALINE;i++){
                        screenbuffer[offset]=linebuffer[i];offset++;
                        }
                read(fh2,linebuffer,CGALINE);
                for(i=0;i!=CGALINE;i++){
                        screenbuffer[offset]=linebuffer[i];offset++;
                        }
                }
            close(fh)  ;
            close(fh2) ;
            return 0   ;

}

int cread(char *name)
{
 int status;


 if((status=B_READ(name))!=0)
     if((status=PCXREAD(name))==-1)
         return(-1);
         setcrtmode(ADAPTER);
  return 0;
}


/* return the color value of the pixel at x, y */
char getpixel(int x, int y)
{
    union REGS inregs, outregs;

    inregs.h.ah = '\x0d';
    inregs.x.cx = x;
    inregs.x.dx = y;

    int86(0x10, &inregs,&outregs);
    return outregs.h.al;
}

void putpixel(int x, int y,int pixelvalue)
{
    union REGS inregs, outregs;

    inregs.h.ah = '\x0c';
    inregs.h.al = pixelvalue;
    inregs.x.cx = x;
    inregs.x.dx = y;

    int86(0x10, &inregs,&outregs);
}


int cload()
{
    unsigned int y,inset=0,offset=0;

    for(y=0;y<200;){
    movedata(FP_SEG(screenbuffer), FP_OFF(screenbuffer)+offset,
                   FRAMEBUFFER,(CGALEAF[0]+inset),CGALINE);
                   offset+=CGALINE;
                   y++;
    movedata(FP_SEG(screenbuffer), FP_OFF(screenbuffer)+offset,
                   FRAMEBUFFER,(CGALEAF[1]+inset),CGALINE);
                   offset+=CGALINE;
                   inset+=CGALINE;
                   y++;
                   }

     return(0);

}

       int topx     = 0;
       int topy     = 0;
       int botx     = 279;
       int boty     = 191;


int lineup()
{
     int x,y,temp;
     char c=1;

       do{

            if(c==ESCKEY)return -1;
            cload();

            /* draw a visible box */
            for(x=topx;x<=botx;x++)
            {
                if(getpixel(x,topy))putpixel(x,topy,0);
                else putpixel(x,topy,3);
            }
            for(y=topy+1;y<boty;y++)
            {
                if(getpixel(topx,y))putpixel(topx,y,0);
                else putpixel(topx,y,3);
                if(getpixel(botx,y))putpixel(botx,y,0);
                else putpixel(botx,y,3);
            }
            for(x=topx;x<=botx;x++)
            {
                if(getpixel(x,boty))putpixel(x,boty,0);
                else putpixel(x,boty,3);
            }
            c=getch();

            if(c==FUNCKEY)
            {
            c=getch();
            switch(c)
            {
             case UPARROW   :
                               boty-=4;
                               if(boty<=1)boty=1;
                               break;

             case DOWNARROW :  if(boty==199)break;
                               boty++;
                               break;

             case LEFTARROW : botx-=14;
                              if(botx<=14)botx+=14;
                              break;

             case RIGHTARROW: botx+=14;
                              if(botx>=279)botx-=14;
                              break;

            }
            }

            }while(c!=ENTERKEY);



cload();
return 0;
}
int OrangeBlackWhite(char *name)
{

FILE *fp;

/* a buffer for the byte pair */
char bytebuf[41];
unsigned char inbuf[282],outbuf[282];
unsigned char bit[7];
unsigned char bytewidth,rasters;
int pixels;

int x,xx,xxx,y,bytes;


   cload();

   if(boty<200)boty++;
   else topy--;

   if(botx>318)
   {
    topx--;
    botx--;
   }

   pixels    = (botx-topx)+1;
   rasters   = (boty-topy);
   bytewidth = (unsigned char)(pixels/7);

   fp = fopen(name,"wb");

   /* create a header if we are writing a RAG file         */
   /* meaning is raster width in bytes x number of rasters */

     fputc(bytewidth,fp);
     fputc(rasters,fp);

   for(y=topy;y<boty;y++)
   {

     /* start by assuming everything is black*/
     for(x=0;x<282;x++)outbuf[x]=0;
     for(x=0;x<41;x++)bytebuf[x]=0;

     /* next accumulate the white values */

     for(x=0;x<pixels;x++)
     {
       inbuf[x]=getpixel(x+topx,y);
       if(inbuf[x] == 3)outbuf[x]  = 1;
       }

      /* next check for secondary color */
      inbuf[280]=inbuf[279];
      xx=1;
      xxx=2;
      for(x=0;x<pixels;x++)
      {
        /* if we have blue write it out */

        if(inbuf[x]  == 1 && inbuf[xx]  == 1)
           {
           if(x%2==0)
               {
               outbuf[x]  = 1;
               outbuf[xx] = 0;
               }
           else
           {
              outbuf[xx]  =  1;
              outbuf[xxx] =  0;
           }
           }

          /* and if we have orange write it out */
        if(inbuf[x]  == 2 && inbuf[xx]  == 2 )
           {
           if(x%2==0)
               {
               outbuf[x]  = 0;
               outbuf[xx] = 1;
               }
           else
           {
              outbuf[xx]  =  0;
              outbuf[xxx] =  1;
           }
           }
           xx++;
           xxx++;
           }

         /*  now pack the raster and write out the file */

          x = 0;
          for(bytes=0;bytes<bytewidth;bytes++)
          {
          for(xx=0;xx<7;xx++)
          {
            bit[xx]=outbuf[x];
            x++;
            }
          bytebuf[bytes]=(0x80     |bit[6]<<6|bit[5]<<5|bit[4]<<4|
                          bit[3]<<3|bit[2]<<2|bit[1]<<1|bit[0]);
          fputc(bytebuf[bytes],fp);
          }

       /* make another pass and loop until finished */
       }
      fclose(fp);
      return 0;

}

main(int argc,char *argv[])
{
   int status,d;
   char c;

   char buf1[66],buf2[66];
   char bline[66],rline[66];
   char *wordptr;

    switch (argc)
        {
        case 2:

          printf("Enter Bottom Line  : ");
                  gets(bline);
          printf("Enter Right Margin : ");
                  gets(rline);
          while(kbhit())getch();
          botx  = ((atoi(rline)/14)*14)+1; /* multiple of 14 */
          if(botx > 279 || botx < 14)botx=279;

          boty  = (atoi(bline));
          if(boty > 191 || boty < 1)boty =191;

          STUFF_BUFF();

          if((status=cread(argv[1]))==0)
             {
                   if(!lineup())
                   {
                   strcpy(buf1,argv[1]);
                   wordptr=strtok(buf1,".");
                   sprintf(buf2,"%s.RAG",buf1);
                   OrangeBlackWhite(buf2);
                   }
                }

                setcrtmode(TEXT);
       default:
                break;
        }

    exit(0);
}

